﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DevExpress.XtraEditors.Controls;

namespace RadinfFakturer
{
    public partial class Fakturer : Form
    {
        #region Members
        private ErrorProvider _errorProvider = new ErrorProvider();

        public static FakturerDataSet DataSource = new FakturerDataSet();
        public static List<string> Logs = new List<string>();
        #endregion

        #region Constructor
        public Fakturer()
        {
            InitializeComponent();
            initializeLookUps();
            loadData();
            setDataBinding();
            initializeInvoice();
        }

        private void initializeInvoice()
        {
            FakturerDataSet.INVOICERow invoiceDR = DataSource.INVOICE.NewINVOICERow();
            invoiceDR.CREATE_DATE = DateTime.Today;
            invoiceDR.SELL_DATE = DateTime.Today;
            invoiceDR.TYPE = this.leType.Properties.Items[0];
            invoiceDR.PAYMENT_TYPE = this.lePaymentType.Properties.Items[0];
            DataSource.INVOICE.Rows.Add(invoiceDR);
        }

        private void setDataBinding()
        {
            deCreateDate.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "CREATE_DATE"));
            deSellDate.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "SELL_DATE"));
            textEdit3.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "INVOICE_NUMBER"));
            leType.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "TYPE"));
            lePaymentType.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "PAYMENT_TYPE"));
            tePaymentDate.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "PAYMENT_DATE"));

            teContrName.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "CNTR_NAME"));
            teContrAddress.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "CNTR_ADDRESS"));
            teContrZipCode.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "CNTR_ZIP_CODE"));
            teContrCity.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "CNTR_CITY"));
            teContrNIP.DataBindings.Add(new Binding("EditValue", DataSource.INVOICE, "CNTR_NIP"));

            gcContractor.DataSource = DataSource.CONTRACTOR;
            gcItem.DataSource = DataSource.ITEM;
        }

        private void initializeLookUps()
        {
            ComboBoxItemCollection docTypeCollection = this.leType.Properties.Items;
            docTypeCollection.BeginUpdate();
            try
            {
                foreach (DocumentType docType in Globals.DOC_TYPES)
                {
                    docTypeCollection.Add(docType);
                }
            }
            finally
            {
                docTypeCollection.EndUpdate();
            }            

            ComboBoxItemCollection vatCollection = this.repVAT.Items;
            vatCollection.BeginUpdate();
            try
            {
                foreach(Vat vat in Globals.VAT)
                {
                    vatCollection.Add(vat);
                }
            }
            finally
            {
                vatCollection.EndUpdate();
            }

            ComboBoxItemCollection measureCollection = this.repMeasure.Items;
            measureCollection.BeginUpdate();
            try
            {
                foreach (string measure in Globals.MEASURE)
                {
                    measureCollection.Add(measure);
                }
            }
            finally
            {
                measureCollection.EndUpdate();
            }

            ComboBoxItemCollection paymentTypeCollection = this.lePaymentType.Properties.Items;
            paymentTypeCollection.BeginUpdate();
            try
            {
                foreach (PaymentType paymentType in Globals.PAYMENT_TYPES)
                {
                    paymentTypeCollection.Add(paymentType);
                }
            }
            finally
            {
                paymentTypeCollection.EndUpdate();
            }
        }
        #endregion

        #region Load / Save
        private void loadData()
        {
            string dataFilePath = Globals.XML_FILES.RADINF_FAKTURER_DATA;
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                if (!File.Exists(dataFilePath))
                    createDataFile(Globals.XML_FILES.RADINF_FAKTURER_DATA_DIR, dataFilePath);

                DataSource.ReadXml(dataFilePath);

                Cursor.Current = Cursors.Default;
            }
            catch (Exception exc)
            {
                RadinfTools.ShowError("Fakturer.loadData()", exc.Message);
            }
        }

        private void saveData()
        {
            DataSource.INVITEM.Clear();
            DataSource.ITEM.Clear();            
            DataSource.INVOICE.Clear();            
            DataSource.AcceptChanges();

            string dataFilePath = Globals.XML_FILES.RADINF_FAKTURER_DATA;
            try
            {
                if (!File.Exists(dataFilePath))
                    createDataFile(Globals.XML_FILES.RADINF_FAKTURER_DATA_DIR, dataFilePath);

                DataSource.WriteXml(dataFilePath);
            }
            catch (Exception exc)
            {
                RadinfTools.ShowError("Fakturer.saveData()", exc.Message);
            }
        }

        private void createDataFile(string directory, string fileName)
        {
            FileInfo fi = new FileInfo(fileName);
            if (Directory.Exists(directory))
            {
                fi.Create();
            }
            else
            {
                Directory.CreateDirectory(directory);
                fi.Create();
            }
        }
        #endregion

        #region Tools
        private void setGridFilter(string filter)
        {
            ((DataView)this.gvContractor.DataSource).RowFilter = filter;
        }

        private double countNetto(double brutto, Vat vat)
        {
            double value = -1;
            value = brutto / (vat.Value + 1);
            return Math.Round(value, 4, MidpointRounding.AwayFromZero);
        }

        private double countVat(double brutto,Vat vat)
        {
            double value = -1;
            value = (brutto * (vat.Value * 100)) / (100 + (vat.Value * 100));
            return Math.Round(value, 2, MidpointRounding.AwayFromZero); 
        }

        private void prepareInvoice4Printing()
        {
            double bruttoValue = 0;
            double nettoValue = 0;
            double vatValue = 0;
            foreach (FakturerDataSet.ITEMRow itemDR in DataSource.ITEM.Rows)
            {
                if (itemDR.RowState != DataRowState.Deleted)
                {
                    bruttoValue += itemDR.BRUTTO_VALUE;
                    nettoValue += itemDR.NETTO_VALUE;
                    vatValue += itemDR.VAT_VALUE;
                }
            }
            if (this.lePaymentType.EditValue is PaymentType)
            {
                PaymentType paymentType = this.lePaymentType.EditValue as PaymentType;
                if (paymentType.Value == Globals.PAYMENT_TYPE.CASH)
                {
                    DataSource.INVOICE[0].PAYMENT_DATE = "Zapłacono gotówką";
                }
            }
            DataSource.INVOICE[0].TO_PAY = Money.getValue(bruttoValue);
            DataSource.INVOICE[0].BRUTTO_VALUE = displayPrice(bruttoValue);
            DataSource.INVOICE[0].NETTO_VALUE = displayPrice(nettoValue);
            DataSource.INVOICE[0].VAT_VALUE = displayPrice(vatValue);
            countVAT23();
            countVAT8();
            countVAT5();
            prepareItems4Printing();
        }

        private void countVAT23()
        {
            double vatValue = 0;
            double nettoValue = 0;
            double bruttoValue = 0;
            foreach (FakturerDataSet.ITEMRow itemDR in DataSource.ITEM.Rows)
            {
                if(itemDR.RowState != DataRowState.Deleted && ((Vat)itemDR.VAT).Value == 0.23)
                {
                    vatValue += itemDR.VAT_VALUE;
                    nettoValue += itemDR.NETTO_VALUE;
                    bruttoValue += itemDR.BRUTTO_VALUE;
                }
            }
            DataSource.INVOICE[0].VAT23 = displayPrice(vatValue);
            DataSource.INVOICE[0].NETTO23 = displayPrice(nettoValue);
            DataSource.INVOICE[0].BRUTTO23 = displayPrice(bruttoValue);
        }

        private void countVAT8()
        {
            double vatValue = 0;
            double nettoValue = 0;
            double bruttoValue = 0;
            foreach (FakturerDataSet.ITEMRow itemDR in DataSource.ITEM.Rows)
            {
                if (itemDR.RowState != DataRowState.Deleted && ((Vat)itemDR.VAT).Value == 0.08)
                {
                    vatValue += itemDR.VAT_VALUE;
                    nettoValue += itemDR.NETTO_VALUE;
                    bruttoValue += itemDR.BRUTTO_VALUE;
                }
            }
            DataSource.INVOICE[0].VAT8 = displayPrice(vatValue);
            DataSource.INVOICE[0].NETTO8 = displayPrice(nettoValue);
            DataSource.INVOICE[0].BRUTTO8 = displayPrice(bruttoValue);
        }

        private void countVAT5()
        {
            double vatValue = 0;
            double nettoValue = 0;
            double bruttoValue = 0;
            foreach (FakturerDataSet.ITEMRow itemDR in DataSource.ITEM.Rows)
            {
                if (itemDR.RowState != DataRowState.Deleted && ((Vat)itemDR.VAT).Value == 0.05)
                {
                    vatValue += itemDR.VAT_VALUE;
                    nettoValue += itemDR.NETTO_VALUE;
                    bruttoValue += itemDR.BRUTTO_VALUE;
                }
            }
            DataSource.INVOICE[0].VAT5 = displayPrice(vatValue);
            DataSource.INVOICE[0].NETTO5 = displayPrice(nettoValue);
            DataSource.INVOICE[0].BRUTTO5 = displayPrice(bruttoValue);
        }

        private void prepareItems4Printing()
        {
            DataSource.INVITEM.Clear();
            foreach (FakturerDataSet.ITEMRow itemDR in DataSource.ITEM.Rows)
            {
                if (itemDR.RowState != DataRowState.Deleted)
                {
                    FakturerDataSet.INVITEMRow newDR = DataSource.INVITEM.NewINVITEMRow();
                    newDR.INVOICE = DataSource.INVOICE[0].ID;
                    newDR.LP = RadinfTools.ConvertToString(itemDR.LP);
                    newDR.NAME = itemDR.NAME;
                    newDR.PKWIU = itemDR.PKWIU;
                    newDR.MEASURE = itemDR.MEASURE;
                    newDR.QUANTITY = RadinfTools.ConvertToString(itemDR.QUANTITY);
                    newDR.VAT = RadinfTools.ConvertToString(itemDR.VAT);
                    newDR.NETTO = displayPrice(itemDR.NETTO);
                    newDR.NETTO_VALUE = displayPrice(itemDR.NETTO_VALUE);
                    newDR.VAT_VALUE = displayPrice(itemDR.VAT_VALUE);
                    newDR.BRUTTO_VALUE = displayPrice(itemDR.BRUTTO_VALUE);
                    newDR.BRUTTO = displayPrice(itemDR.BRUTTO);
                    DataSource.INVITEM.Rows.Add(newDR);
                }
            }
        }

        private string displayPrice(double dPrice)
        {
            string decimalSeparator = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
            string sPrice = dPrice.ToString();

            if (sPrice.Contains(decimalSeparator))
            {
                if (sPrice.LastIndexOf(decimalSeparator) == (sPrice.Length - 2))
                    sPrice = sPrice + "0";
            }
            else
                sPrice = sPrice + decimalSeparator + "00";

            return sPrice + " zł";
        }
        #endregion

        #region Validation
        private bool validateAllCtrls()
        {
            bool result = true;
            _errorProvider.Clear();
            result &= validateInvoiceNumber();
            return result;
        }

        private bool validateInvoiceNumber()
        {
            bool result = true;

            if(String.IsNullOrWhiteSpace(RadinfTools.ConvertToString(textEdit3.EditValue)))
            {
                result = false;
                _errorProvider.SetError(this.textEdit3, Globals.ERRORS.REQUIRED);
            }
            return result;
        }

        #endregion

        #region Events
        private void lePaymentType_EditValueChanged(object sender, System.EventArgs e)
        {
            if (this.lePaymentType.EditValue is PaymentType)
            {
                PaymentType selectedPaymentType = this.lePaymentType.EditValue as PaymentType;
                this.tePaymentDate.Enabled = selectedPaymentType.Value == Globals.PAYMENT_TYPE.TRANSFER;
            }
        }

        private void btnSelectContractor_Click(object sender, EventArgs e)
        {
            if (gvContractor.GetDataRow(gvContractor.FocusedRowHandle) != null &&
                gvContractor.GetDataRow(gvContractor.FocusedRowHandle) is FakturerDataSet.CONTRACTORRow)
            {
                FakturerDataSet.CONTRACTORRow contractorDR = (FakturerDataSet.CONTRACTORRow)gvContractor.GetDataRow(gvContractor.FocusedRowHandle);

                teContrName.EditValue = RadinfTools.ConvertToString(contractorDR.NAME);
                teContrAddress.EditValue = RadinfTools.ConvertToString(contractorDR.ADDRESS);
                teContrZipCode.EditValue = RadinfTools.ConvertToString(contractorDR.ZIP_CODE);
                teContrCity.EditValue = RadinfTools.ConvertToString(contractorDR.CITY);
                teContrNIP.EditValue = RadinfTools.ConvertToString(contractorDR.NIP);

                DataSource.INVOICE[0].CNTR_NAME = RadinfTools.ConvertToString(contractorDR.NAME);
                DataSource.INVOICE[0].CNTR_ADDRESS = RadinfTools.ConvertToString(contractorDR.ADDRESS);
                DataSource.INVOICE[0].CNTR_ZIP_CODE = RadinfTools.ConvertToString(contractorDR.ZIP_CODE);
                DataSource.INVOICE[0].CNTR_CITY = RadinfTools.ConvertToString(contractorDR.CITY);
                DataSource.INVOICE[0].CNTR_NIP = RadinfTools.ConvertToString(contractorDR.NIP);               
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnPrint_Click(object sender, EventArgs e)
        {
            if (validateAllCtrls())
            {
                prepareInvoice4Printing();
                DocumentType docType = (DocumentType)this.leType.EditValue;
                string invoiceNumber = RadinfTools.ConvertToString(this.textEdit3.EditValue);
                invoiceNumber = invoiceNumber.Replace('/', '_');
                invoiceNumber = invoiceNumber.Replace('\\', '_');
                if (docType.Value == Globals.DOC_TYPE.RP)
                {
                    InvoiceRP report = new InvoiceRP();
                    report.DataSource = DataSource;
                    report.ExportToPdf("C:\\Faktury\\" + invoiceNumber + ".pdf");
                    report.ShowPreviewDialog();                    
                }
                else if (docType.Value == Globals.DOC_TYPE.VAT)
                {
                    InvoiceVAT report = new InvoiceVAT();
                    report.DataSource = DataSource;
                    report.ExportToPdf("C:\\Faktury\\" + invoiceNumber + ".pdf");
                    report.ShowPreviewDialog();                   
                }
            }
        }

        private void Fakturer_FormClosing(object sender, FormClosingEventArgs e)
        {
            saveData();
        }

        private void searching(object sender, DevExpress.XtraEditors.Controls.ChangingEventArgs e)
        {
            if (sender is DevExpress.XtraEditors.TextEdit)
            {
                DevExpress.XtraEditors.TextEdit textEdit = sender as DevExpress.XtraEditors.TextEdit;

                string searchCriteria = RadinfTools.ConvertToString(e.NewValue);
                if (!String.IsNullOrEmpty(searchCriteria) && !String.IsNullOrEmpty(RadinfTools.ConvertToString(textEdit.Tag)))
                {
                    searchCriteria = RadinfTools.ConvertToString(textEdit.Tag) + " LIKE '" + searchCriteria + "%'";
                    setGridFilter(searchCriteria);
                }
                else
                    setGridFilter(string.Empty);
            }
        }

        private void gvItem_RowUpdated(object sender, DevExpress.XtraGrid.Views.Base.RowObjectEventArgs e)
        {
            if (((DataRowView)e.Row).Row is FakturerDataSet.ITEMRow)
            {
                double brutto;
                double quantity;
                double nettoValue;
                double bruttoValue;
                double netto;

                FakturerDataSet.ITEMRow itemDR = ((DataRowView)e.Row).Row as FakturerDataSet.ITEMRow;
                if (itemDR != null)
                {
                    itemDR.BeginEdit();
                    Vat vat = itemDR.VAT as Vat;
                    try
                    {
                        bool bruttoParse = Double.TryParse(RadinfTools.ConvertToString(itemDR.BRUTTO), out brutto);
                        bool quantityParse = Double.TryParse(RadinfTools.ConvertToString(itemDR.QUANTITY), out quantity);
                        if (bruttoParse && quantityParse)
                        {
                            netto = countNetto(brutto, vat);
                            nettoValue = Math.Round((netto * quantity), 2, MidpointRounding.AwayFromZero);
                            bruttoValue = Math.Round((brutto * quantity), 2, MidpointRounding.AwayFromZero);
                            
                            itemDR.NETTO = netto;
                            itemDR.VAT_VALUE = bruttoValue - nettoValue;
                            itemDR.NETTO_VALUE = nettoValue;
                            itemDR.BRUTTO_VALUE = bruttoValue;
                        }
                    }
                    catch (Exception) { }
                    finally
                    {
                        itemDR.EndEdit();
                    }
                }
            }
        }

        private void gvItem_InitNewRow(object sender, DevExpress.XtraGrid.Views.Grid.InitNewRowEventArgs e)
        {
            FakturerDataSet.ITEMRow itemDR = gvItem.GetDataRow(e.RowHandle) as FakturerDataSet.ITEMRow;
            itemDR.VAT = this.repVAT.Items[0];
            itemDR.MEASURE = this.repMeasure.Items[0].ToString();
        }
        #endregion                
    }
}
